package com.system.core.utils;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import jakarta.servlet.http.HttpServletRequest;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

public class BeanUtil {

    public static void copyDeclaredFields(Object dest, Class<?>[] destClasses, Object src, Class<?>[] srcClasses) {
        try {
            for (int i = 0; i < destClasses.length; i++) {
                Class<?> destClass = destClasses[i];
                for (Field srcField : srcClasses[i].getDeclaredFields()) {
                    try {
                        srcField.setAccessible(true);
                        Field destField = destClass.getDeclaredField(srcField.getName());
                        destField.setAccessible(true);
                        destField.set(dest, srcField.get(src));
                    } catch (NoSuchFieldException ignored) {
                    }
                }
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public static Object getProperty(Object bean, String name) {
        String methodNameSuffix = Character.toUpperCase(name.charAt(0)) + name.substring(1);
        Method method;
        Class<?> c = bean.getClass();
        try {
            method = c.getMethod("get" + methodNameSuffix);
        } catch (NoSuchMethodException e) {
            try {
                method = c.getMethod("is" + methodNameSuffix);
            } catch (NoSuchMethodException e1) {
                try {
                    Field field = c.getField(name);
                    return field.get(bean);
                } catch (NoSuchFieldException e2) {
                    return null;
                } catch (IllegalAccessException e2) {
                    throw new RuntimeException(e);
                }
            }
        }
        try {
            return method.invoke(bean);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    public static void setProperty(Object bean, String name, Object value) {
        try {
            BeanUtils.setProperty(bean, name, value);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> T setValue(T obj, Object... values) {
        for (int i = 0; i < values.length; i += 2) {
            try {
                PropertyUtils.setProperty(obj, (String) values[i], values[i + 1]);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            } catch (NoSuchMethodException e) {
                throw new RuntimeException(e);
            }
        }
        return obj;
    }

    public static <T> T setValueFromNew(Class<T> clazz, Object... values) {
        T obj = getT(clazz);
        return setValue(obj, values);
    }

    public static <T> T copyBeanFromNew(Object from, Class<T> clazz) {
        return copyBeanFromNew(from, clazz, new String[] {});
    }


    public static <T> T copyBeanFromNew(Object from, Class<T> clazz, String... ignores) {
        T obj = getT(clazz);
        org.springframework.beans.BeanUtils.copyProperties(from, obj, ignores);
        return obj;
    }

    private static <T> T getT(Class<T> clazz) {
        T obj;
        try {
            obj = clazz.newInstance();
        } catch (InstantiationException var4) {
            throw new RuntimeException(var4);
        } catch (IllegalAccessException var5) {
            throw new RuntimeException(var5);
        }
        return obj;
    }

    public static <K, T> Map<K, T> setMap(Map<K, T> paramMap, Class<T> clazz, Object... keysAndValues) {
        for (int i = 0; i < keysAndValues.length; i += 2) {
            paramMap.put((K) keysAndValues[i], clazz.cast(keysAndValues[i + 1]));
        }
        return paramMap;
    }

    public static <K, T> Map<K, T> setMapFromNew(Class<T> clazz, Object... keysAndValues) {
        return setMap(new HashMap<K, T>(), clazz, keysAndValues);
    }


    public static HttpServletRequest setHttpAttributes(HttpServletRequest request, Object... values) {
        for (int i = 0; i < values.length; i += 2) {
            request.setAttribute((String) values[i], values[i + 1]);
        }
        return request;
    }

    public static <T> List<T> setValueList(List<T> origin, Object... values) {
        for (T f : origin) {
            BeanUtil.setValue(f, values);
        }
        return origin;
    }

    public static <T, K> List<K> setValueListFromNew(List<T> origin, Class<K> clazz, Object... values) {
        List<K> list = new ArrayList<>();
        for (T f : origin) {
            Object[] a = new Object[values.length];
            for (int i = 0; i < values.length; i += 2) {
                a[i + 1] = values[i + 1];
                try {
                    a[i] = PropertyUtils.getProperty(f, (String) (values[i]));
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException(e);
                }
            }
            list.add(BeanUtil.setValueFromNew(clazz, a));
        }
        return list;
    }

    public static <T> List<T> copyBeanFromNewList(List<?> origin, Class<T> clazz, String... ignores) {
        List<T> newArrayList = new ArrayList<>();
        for (Object f : origin) {
            newArrayList.add(copyBeanFromNew(f, clazz, ignores));
        }
        return newArrayList;
    }

    public static <K, T> List<Map<K, T>> setMapList(List<Map<K, T>> origin, Class<T> clazz, Object... keysAndValues) {
        for (Map<K, T> f : origin) {
            setMap(f, clazz, keysAndValues);
        }
        return origin;
    }

    public static String[] getNullPropertyNames(Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> emptyNames = new HashSet<String>();
        for (java.beans.PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null || isEmpty(srcValue))
                emptyNames.add(pd.getName());
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }

    public static void copyPropertiesIgnoreNull(Object source, Object target) {
        org.springframework.beans.BeanUtils.copyProperties(source, target, getNullPropertyNames(source));
    }

    public static void copyProperties(Object source, Object target) {
        org.springframework.beans.BeanUtils.copyProperties(source, target);
    }

    /**
     * 判断对象是否是空
     *
     * @param object 传入对象
     * @return 如果<code>object.toString()</code>为<code>""</code>、 <code>null</code> 或者空数组, 则返回<code>true</code>
     */
    public static boolean isEmpty(Object object) {
        if (object == null) {
            return true;
        }
        if (object instanceof String) {
            return StringUtils.isEmpty(object.toString());
        }
        if (object.getClass().isArray()) {
            return Array.getLength(object) == 0;
        }

        return false;
    }
    
    public static Map<String, String> beanToMap(Object obj,boolean nullField) {
        Map<String, String> map = new HashMap<>();
        // 获取对象的所有字段
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            // 设置可访问私有字段
            field.setAccessible(true);
            try {
            	String value = null;
            	if(field.get(obj)!=null) {
            		value = String.valueOf(field.get(obj));
            	}
            	if(!nullField && StringUtils.isNotBlank(value)) {
            		map.put(field.getName(), value);
            	} else if(nullField) {
            		map.put(field.getName(), value);
            	}
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return map;
    }
}
